#pragma once
#include <pthread.h>
#include <queue>
#include <mutex>

namespace lsh
{
    template <typename T>
    class blockqueue
    {
    public:
        blockqueue(int cap)
            : _cap(cap)
        {
            pthread_mutex_init(&mutex, nullptr);
            pthread_cond_init(&producter, nullptr);
            pthread_cond_init(&consumer, nullptr);
        }
        ~blockqueue()
        {
            pthread_mutex_destroy(&mutex);
            pthread_cond_destroy(&producter);
            pthread_cond_destroy(&consumer);
        }
        // 生产者往阻塞队列中放入数据
        void push(const T &data)
        {
            pthread_mutex_lock(&mutex);
            // 首先检查队列中是否为满
            while (isFull())
            {
                pthread_cond_wait(&producter, &mutex);
            }
            que.push(data);
            pthread_cond_signal(&consumer);
            pthread_mutex_unlock(&mutex);
        }

        void pop(T *data)
        {
            pthread_mutex_lock(&mutex);
            while (isEmpty())
            {
                pthread_cond_wait(&consumer, &mutex);
            }
            *data = que.front();
            que.pop();
            pthread_cond_signal(&producter);
            pthread_mutex_unlock(&mutex);
        }

    private:
        std::queue<T> que;
        int _cap;
        pthread_mutex_t mutex;
        pthread_cond_t producter;
        pthread_cond_t consumer;

        bool isFull()
        {
            return que.size() == _cap;
        }
        bool isEmpty()
        {
            return que.size() == 0;
        }
    };
}
